package com.sunwayworld.basemodule.rm.train.exam.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.sunwayworld.basemodule.rm.train.exam.bean.LimsCoreExamBean;
import com.sunwayworld.basemodule.rm.train.exam.bean.LimsCoreExamQuestionBean;
import com.sunwayworld.basemodule.rm.train.exam.dao.LimsCoreExamQuestionDao;
import com.sunwayworld.basemodule.rm.train.exam.service.LimsCoreExamQuestionService;
import com.sunwayworld.basemodule.rm.train.exam.service.LimsCoreExamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;


import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.audit.aunnotation.Audit;
import com.sunwayworld.framework.audit.constant.AuditConstant;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.context.LocalContextHelper;
import com.sunwayworld.framework.context.concurrent.GikamConcurrentLocker;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.PersistableMetadataHelper;
import com.sunwayworld.module.mdm.user.bean.CoreUserBean;
import com.sunwayworld.module.sys.metadata.service.CoreTableService;

@GikamBean
@Repository
public class LimsCoreExamQuestionServiceImpl implements LimsCoreExamQuestionService {
    @Autowired
    private LimsCoreExamQuestionDao limsCoreExamQuestionDao;
    
    @Autowired
    @Lazy
    private LimsCoreExamService limsCoreExamService;
    
    @Override
    @SuppressWarnings("unchecked")
    public LimsCoreExamQuestionDao getDao() {
        return limsCoreExamQuestionDao;
    }
    
    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    @Audit(AuditConstant.INSERT)
    public Long insert(RestJsonWrapperBean wrapper) {
        List<LimsCoreExamQuestionBean> examQuestionList = wrapper.parse(LimsCoreExamQuestionBean.class);
        if (examQuestionList.isEmpty()) {
            return null;
        }
        
        GikamConcurrentLocker.block(getDao().getTable());
        
        List<Long> examIdList = examQuestionList.stream().map(LimsCoreExamQuestionBean::getExamId).distinct().collect(Collectors.toList());
        List<LimsCoreExamQuestionBean> oriExamQuestionList = selectListByFilter(SearchFilter.instance().match("EXAMID", examIdList).filter(MatchPattern.OR));
        
        CoreUserBean currentUser = LocalContextHelper.getLoginUser();
        LocalDateTime currentTime = LocalDateTime.now();
        List<LimsCoreExamBean> examList4Update = new ArrayList<>();
        
        examIdList.forEach(e -> {
            LimsCoreExamBean exam = new LimsCoreExamBean();
            
            List<LimsCoreExamQuestionBean> subExamQuestionList = examQuestionList.stream().filter(f -> f.getExamId().equals(e)).collect(Collectors.toList());
            List<LimsCoreExamQuestionBean> subOriExamQuestionList = oriExamQuestionList.stream().filter(f -> f.getExamId().equals(e)).collect(Collectors.toList());
            
            long singleChoiceQty = subExamQuestionList.stream().filter(f -> "singleChoice".equals(f.getExt$().get("questiontype"))).count();
            long oriSingleChoiceQty = subOriExamQuestionList.stream().filter(f -> "singleChoice".equals(f.getExt$().get("questiontype"))).count();
            long totalSingleChoiceQty = singleChoiceQty + oriSingleChoiceQty;
            
            long multipleChoiceQty = subExamQuestionList.stream().filter(f -> "multipleChoice".equals(f.getExt$().get("questiontype"))).count();
            long oriMultipleChoiceQty = subOriExamQuestionList.stream().filter(f -> "multipleChoice".equals(f.getExt$().get("questiontype"))).count();
            long totalMultipleChoiceQty = multipleChoiceQty + oriMultipleChoiceQty;
            
            long completionQty = subExamQuestionList.stream().filter(f -> "completion".equals(f.getExt$().get("questiontype"))).count();
            long oriCompletionQty = subOriExamQuestionList.stream().filter(f -> "completion".equals(f.getExt$().get("questiontype"))).count();
            long totalCompletionQty = completionQty + oriCompletionQty;
            
            long judgementQty = subExamQuestionList.stream().filter(f -> "judgement".equals(f.getExt$().get("questiontype"))).count();
            long oriJudgementQty = subOriExamQuestionList.stream().filter(f -> "judgement".equals(f.getExt$().get("questiontype"))).count();
            long totalJudgementQty = judgementQty + oriJudgementQty;
            
            long shortAnswerQty = subExamQuestionList.stream().filter(f -> "shortAnswer".equals(f.getExt$().get("questiontype"))).count();
            long oriShortAnswerQty = subOriExamQuestionList.stream().filter(f -> "shortAnswer".equals(f.getExt$().get("questiontype"))).count();
            long totalShortAnswerQty = shortAnswerQty + oriShortAnswerQty;
            
            exam.setId(e);
            exam.setLastUpdatedById(currentUser.getId());
            exam.setLastUpdatedByName(currentUser.getUserName());
            exam.setLastUpdatedTime(currentTime);
            exam.setSingleChoiceQty(totalSingleChoiceQty);
            exam.setMultipleChoiceQty(totalMultipleChoiceQty);
            exam.setJudgementQty(totalJudgementQty);
            exam.setShortAnswerQty(totalShortAnswerQty);
            exam.setCompletionQty(totalCompletionQty);
            
            examList4Update.add(exam);
        });
        
        List<Long> idList = ApplicationContextHelper.getNextIdentityList(examQuestionList.size());
        for (int i = 0; i < examQuestionList.size(); i++) {
            Long id = idList.get(i);
            examQuestionList.get(i).setId(id);
        }
        
        getDao().insert(examQuestionList);
        limsCoreExamService.getDao().update(examList4Update, "LASTUPDATEDBYID", "LASTUPDATEDBYNAME", "LASTUPDATEDTIME", "SINGLECHOICEQTY", "MULTIPLECHOICEQTY", "JUDGEMENTQTY", "SHORTANSWERQTY", "COMPLETIONQTY");
        
        return idList.get(0);
    }
    
    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.DELETE)
    @Audit(AuditConstant.DELETE)
    public void delete(RestJsonWrapperBean wrapper) {
        List<LimsCoreExamQuestionBean> examQuestionList = wrapper.parse(this.getDao().getType());
        if (examQuestionList.isEmpty()) {
            return;
        }
        
        GikamConcurrentLocker.block(getDao().getTable());
        
        List<Long> examIdList = examQuestionList.stream().map(LimsCoreExamQuestionBean::getExamId).distinct().collect(Collectors.toList());
        List<LimsCoreExamQuestionBean> oriExamQuestionList = selectListByFilter(SearchFilter.instance().match("EXAMID", examIdList).filter(MatchPattern.OR));
        
        CoreUserBean currentUser = LocalContextHelper.getLoginUser();
        LocalDateTime currentTime = LocalDateTime.now();
        
        List<LimsCoreExamBean> examList4Update = new ArrayList<>();
        examIdList.forEach(e -> {
            LimsCoreExamBean exam = new LimsCoreExamBean();
            
            List<LimsCoreExamQuestionBean> subExamQuestionList = examQuestionList.stream().filter(f -> f.getExamId().equals(e)).collect(Collectors.toList());
            List<LimsCoreExamQuestionBean> subOriExamQuestionList = oriExamQuestionList.stream().filter(f -> f.getExamId().equals(e)).collect(Collectors.toList());
            
            long singleChoiceQty = subExamQuestionList.stream().filter(f -> "singleChoice".equals(f.getExt$().get("questiontype"))).count();
            long oriSingleChoiceQty = subOriExamQuestionList.stream().filter(f -> "singleChoice".equals(f.getExt$().get("questiontype"))).count();
            long totalSingleChoiceQty = oriSingleChoiceQty - singleChoiceQty;
            
            long multipleChoiceQty = subExamQuestionList.stream().filter(f -> "multipleChoice".equals(f.getExt$().get("questiontype"))).count();
            long oriMultipleChoiceQty = subOriExamQuestionList.stream().filter(f -> "multipleChoice".equals(f.getExt$().get("questiontype"))).count();
            long totalMultipleChoiceQty = oriMultipleChoiceQty - multipleChoiceQty;
            
            long completionQty = subExamQuestionList.stream().filter(f -> "completion".equals(f.getExt$().get("questiontype"))).count();
            long oriCompletionQty = subOriExamQuestionList.stream().filter(f -> "completion".equals(f.getExt$().get("questiontype"))).count();
            long totalCompletionQty = completionQty + oriCompletionQty;
            
            long judgementQty = subExamQuestionList.stream().filter(f -> "judgement".equals(f.getExt$().get("questiontype"))).count();
            long oriJudgementQty = subOriExamQuestionList.stream().filter(f -> "judgement".equals(f.getExt$().get("questiontype"))).count();
            long totalJudgementQty = oriJudgementQty - judgementQty;
            
            long shortAnswerQty = subExamQuestionList.stream().filter(f -> "shortAnswer".equals(f.getExt$().get("questiontype"))).count();
            long oriShortAnswerQty = subOriExamQuestionList.stream().filter(f -> "shortAnswer".equals(f.getExt$().get("questiontype"))).count();
            long totalShortAnswerQty = oriShortAnswerQty - shortAnswerQty;
            
            exam.setId(e);
            exam.setLastUpdatedById(currentUser.getId());
            exam.setLastUpdatedByName(currentUser.getUserName());
            exam.setLastUpdatedTime(currentTime);
            exam.setSingleChoiceQty(totalSingleChoiceQty);
            exam.setMultipleChoiceQty(totalMultipleChoiceQty);
            exam.setJudgementQty(totalJudgementQty);
            exam.setShortAnswerQty(totalShortAnswerQty);
            exam.setCompletionQty(totalCompletionQty);
            examList4Update.add(exam);
        });
        
        limsCoreExamService.getDao().update(examList4Update, "LASTUPDATEDBYID", "LASTUPDATEDBYNAME", "LASTUPDATEDTIME", "SINGLECHOICEQTY", "MULTIPLECHOICEQTY", "JUDGEMENTQTY", "SHORTANSWERQTY", "COMPLETIONQTY");

        CoreTableService tableService = ApplicationContextHelper.getBean(CoreTableService.class);
        examQuestionList.forEach(t -> tableService.deleteCascade(PersistableMetadataHelper.getTableName(getDao().getType()), t.getId()));
        
    }
}
